package ru.spb.osll.myfit.wikiverifier;

import ru.spb.osll.myfit.common.*;
import ru.spb.osll.myfit.server.parser.TableUtils;
import ru.spb.osll.myfit.wikiverifier.exception.TableStyleNotSupportedException;
import ru.spb.osll.myfit.wikiverifier.exception.UnknownTableStyleException;
import ru.spb.osll.myfit.wikiverifier.exception.WikiVerifierException;
import ru.spb.osll.myfit.wikiverifier.result.PageVerificationResult;
import ru.spb.osll.myfit.wikiverifier.result.TableVerificationResult;
import ru.spb.osll.myfit.wikiverifier.result.VerificationResultType;
import ru.spb.osll.myfit.wikiverifier.verifier.*;
import util.GracefulNamer;

import java.util.*;

public class WikiVerifier {
	private HashMap<TableStyle, TableVerifier> m_verifiers;
	private SuggestionProvider m_suggestionProvider;
	Map<String, Class<?>> m_fixtures;

	public WikiVerifier(List<Table> templates, Map<String, Class<?>> fixtures) {
		m_verifiers = new HashMap<TableStyle, TableVerifier>();
		m_verifiers.put(TableStyle.ONE_LINE_FIXTIRE, new OneLineFixtureVerifier(
				fixtures));
		m_verifiers.put(TableStyle.DO_FIXTURE, new DoFixtureVerifier(fixtures));
		m_verifiers.put(TableStyle.SETUP_FIXTURE, new SetUpFixtureVerifier(
				fixtures));
        m_verifiers.put(TableStyle.COMMENT_FIXTURE, new CommentFixtureVerifier());
		m_suggestionProvider = new SuggestionProvider(templates);
		m_fixtures = fixtures;
	}

	public PageVerificationResult verifyPage(Page page, boolean makeSuggestion) {
		PageVerificationResult result = new PageVerificationResult();

		for (int i = 0; i < page.countPageElements(); i++) {
		  PageElement pageElement = page.getElement(i);
		  if(pageElement instanceof Table){
		    Table table = (Table) pageElement;
	      TableVerificationResult tableResult = verifyTable(table);
	      if (tableResult.getResult() != VerificationResultType.OK
	          && makeSuggestion) {
	        m_suggestionProvider.provideSuggestion(tableResult);
	      }
	      result.addTableResult(tableResult);    
		  }
		}

		return result;
	}

	private TableVerificationResult verifyTable(Table table) {
		try {
			if (table.getStyle() == TableStyle.UNKNOWN_FIXTURE || table.getStyle() == TableStyle.ONE_LINE_FIXTIRE || table.getStyle() == TableStyle.COMMENT_FIXTURE) {
				table.setStyle(TableUtils.getTableStyle(getFixtureClass(table)));
			}

			if (!m_verifiers.containsKey(table.getStyle())) {
			  if(table.getStyle() == TableStyle.UNKNOWN_FIXTURE){
			    throw new UnknownTableStyleException("Unknown Table Style");
			  }else{
			    throw new TableStyleNotSupportedException("Table style "
	            + table.getStyle() + " not supported");	    
			  }
			}

			return m_verifiers.get(table.getStyle()).verifyTable(table);

		} catch (WikiVerifierException e) {
			return new TableVerificationResult(VerificationResultType.FAILURE,
					table, e);
		}
	}

	private Class<?> getFixtureClass(Table table) {
		Iterator<Vector<TableCell>> tableIter = table.getData().iterator();

		if (!tableIter.hasNext()) {
			return null;
		}

		Vector<TableCell> line = tableIter.next();
		String className = getClassName(line);
        if (m_fixtures.containsKey(className + "Fixture")) {
			className = className + "Fixture";
		}

		if (!m_fixtures.containsKey(className)) {
			return null;
		}

		return m_fixtures.get(className);
	}

	private String getClassName(Vector<TableCell> tableLine) {
		return GracefulNamer.disgrace(tableLine.get(0).getText());
	}

}
